﻿using DataSync.Entity;
using log4net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Boco.CommonLib;
using System.Data;
using DataSync.Common;
using System.Xml.Linq;

namespace DataSync.Proc.Reader
{
    class DBReader : DataSyncReaderBase
    {
        private static ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        protected DBReaderConfig CurReaderConf; //文件读取配置
        protected DBParseConfig CurParseConf; //文件解析配置
        protected IDbConnection ConnIns; //当前数据库连接
        private CustParseExtData extCustParseData;
        Dictionary<string, ICustParse> custParseIns; //转换器列表

        private readonly string CNT_Sql_Data = "Sql_Data";
        private readonly string CNT_Sql_Pre = "Sql_Pre";
        private readonly string CNT_Sql_After = "Sql_Post";

        protected override void ReadConfig(XElement xmlnode)
        {
            //读取配置
            var dbconf = xmlnode.Element("DBConfig");
            if (dbconf == null)
            {
                throw new ApplicationException("DBConfig配置不正确");
            }
            DBReaderConfig conf = new DBReaderConfig()
            {
                DBType = (DataBaseType)Enum.Parse(typeof(DataBaseType), dbconf.GetAttribute("DBType"), false),
                ConnString = dbconf.GetAttribute("ConnString"),
                BathDataCount = dbconf.GetAttributesAsInt("BathDataCount")
            };
            //Sql
            conf.Sqls = new Dictionary<string, string>();
            var sqls = xmlnode.Element("Sqls").Elements("Sql");
            foreach (var item in sqls)
            {
                var id = item.GetAttribute("id");
                if (conf.Sqls.ContainsKey(id))
                {
                    conf.Sqls[id] = item.Value;
                }
                else
                {
                    conf.Sqls.Add(id, item.Value);
                }
            }
            //检查正确性
            if (string.IsNullOrEmpty(conf.ConnString))
            {
                throw new ApplicationException("DBConfig:ConnString配置不正确");
            }
            if (conf.Sqls.Count == 0 || string.IsNullOrEmpty(conf.Sqls[CNT_Sql_Data]))
            {
                throw new ApplicationException("DBConfig:Sql配置不能为空");
            }
            CurReaderConf = conf;

            //解析配置
            var parseconf = xmlnode.Element("DataParse");
            if (parseconf == null)
            {
                throw new ApplicationException("DataParse配置不正确");
            }
            DBParseConfig pconf = new DBParseConfig();

            //读取解析字段
            var fnode = parseconf.Element("Fields").Elements("Field");
            pconf.Fields = new List<ParseField>();
            pconf.DataEnums = new Dictionary<string, List<DataEnumItem>>();
            foreach (var item in fnode)
            {
                pconf.Fields.Add(new ParseField()
                {
                    //Index = item.GetAttributesAsInt("Index"),
                    Name = item.GetAttribute("Name"),
                    //Col = item.GetAttribute("Col"),
                    //FieldType = item.GetAttribute("FieldType"),
                    ConvertType = item.GetAttribute("ConvertType"),
                    ConvertParams = item.GetAttribute("ConvertParams"),
                    //Iskey = item.GetAttributesAsBool("Iskey")
                });
            }
            //读取字典解析
            var enode = parseconf.Element("DataEnums");
            if (enode != null)
            {
                var enodes = enode.Elements("DataEnum");
                foreach (var eitem in enodes)
                {
                    List<DataEnumItem> items = new List<DataEnumItem>();
                    var itemNodes = eitem.Elements("Item");
                    foreach (var nitem in itemNodes)
                    {
                        items.Add(new DataEnumItem()
                        {
                            Key = nitem.GetAttribute("Key"),
                            Value = nitem.GetAttribute("Value")
                        });

                    }
                    var name = eitem.GetAttribute("Name");
                    if (pconf.DataEnums.ContainsKey(name))
                    {
                        pconf.DataEnums[name] = items;
                    }
                    else
                        pconf.DataEnums.Add(name, items);
                }
            }

            CurParseConf = pconf;
            extCustParseData = new CustParseExtData();
            extCustParseData.DataEnums = this.CurParseConf.DataEnums;
            extCustParseData.DicData = new Dictionary<string, string>();

            //初始化 转换器
            custParseIns = new Dictionary<string, ICustParse>();
            foreach (var item in CurParseConf.Fields)
            {
                if (!string.IsNullOrEmpty(item.ConvertType) && !custParseIns.ContainsKey(item.ConvertType))
                {
                    var custParser = InterfaceFactory.GetCustParse(item.ConvertType);
                    custParser.Init(xmlnode);
                    custParseIns.Add(item.ConvertType, custParser);
                }
            }
        }

        protected IDbConnection GetCurConn()
        {
            if (ConnIns == null)
            {
                ConnIns = DBFactory.GetConn(this.CurReaderConf);
            }
            if (ConnIns.State == ConnectionState.Closed || ConnIns.State == ConnectionState.Broken)
            {
                ConnIns.Open();
            }
            return ConnIns;
        }

        protected override void Prepare()
        {
            //执行前
            if (CurReaderConf.Sqls.ContainsKey(CNT_Sql_Pre) && !string.IsNullOrEmpty(CurReaderConf.Sqls[CNT_Sql_Pre]))
            {
                var sql = CurReaderConf.Sqls[CNT_Sql_Pre];
                log.DebugFormat("Parse执行Sql_Pre:{0}", sql);
                using (var conn = GetCurConn())
                {
                    var cmd = conn.CreateCommand();
                    cmd.CommandText = sql;
                    cmd.ExecuteNonQuery();
                }

            }
        }

        protected override void Post()
        {
            //执行前
            if (CurReaderConf.Sqls.ContainsKey(CNT_Sql_After) && !string.IsNullOrEmpty(CurReaderConf.Sqls[CNT_Sql_After]))
            {
                var sql = CurReaderConf.Sqls[CNT_Sql_After];
                log.DebugFormat("Parse执行Sql_Post:{0}", sql);
                using (var conn = GetCurConn())
                {
                    var cmd = conn.CreateCommand();
                    cmd.CommandText = sql;
                    cmd.ExecuteNonQuery();
                }
            }
        }

        public override void Close()
        {
            if (ConnIns != null)
            {
                if (ConnIns.State == ConnectionState.Open)
                {
                    ConnIns.Close();
                }
                ConnIns = null;
            }
            base.Close();
        }

        protected override int ReadData()
        {
            var proNum = 0;
            //开始执行
            string sql = this.CurReaderConf.Sqls[CNT_Sql_Data];

            using (var conn = GetCurConn())
            {
                var cmd = conn.CreateCommand();
                //分页检查
                log.Debug("查询原数据记录数");
                string sql_count = string.Format(DBFactory.FormatSql_Count(this.CurReaderConf.DBType), sql);
                cmd.CommandText = sql_count;
                var rt = (Int32)cmd.ExecuteScalar();
                if (rt <= 0)
                {
                    log.InfoFormat("Sql:[{0}]查询无数据", sql_count);
                }
                else
                {
                    log.DebugFormat("读取数据：[{0}]", sql);
                    var da = DBFactory.GetDataAdapter(this.CurReaderConf.DBType);
                    DataSet ds = new DataSet();
                    if (rt > this.CurReaderConf.BathDataCount && this.CurReaderConf.BathDataCount >= 0)
                    {
                        //分页
                        string sql_page_temp = DBFactory.FormatSql_Page(this.CurReaderConf.DBType);
                        int pagenum = (int)Math.Ceiling((double)rt / this.CurReaderConf.BathDataCount);
                        int skip = 0;
                        int pagesize = this.CurReaderConf.BathDataCount;
                        for (int i = 0; i < pagenum; i++)
                        {
                            log.DebugFormat("分页读取第{0}页数据", i + 1);
                            skip = i * pagesize;
                            string cursql = string.Format(sql_page_temp, skip, pagesize, sql);
                            ds.Clear();
                            cmd.CommandText = cursql;
                            da.SelectCommand = cmd;
                            da.Fill(ds);
                            if (ds != null && ds.Tables.Count > 0)
                            {
                                proNum += this.CurWriter.Execute(DtToList(ds.Tables[0])); //执行
                            }
                            else
                            {
                                log.WarnFormat("第{0}页数据查询数据为空", i + 1);
                            }
                        }
                    }
                    else
                    {
                        //不分页
                        cmd.CommandText = sql;
                        da.SelectCommand = cmd;
                        da.Fill(ds);
                        if (ds != null && ds.Tables.Count > 0)
                        {
                            proNum = this.CurWriter.Execute(DtToList(ds.Tables[0])); //执行
                        }
                        else
                        {
                            log.WarnFormat("读取数据为空");
                        }
                    }
                }
            }

            return proNum;
        }

        IList<Dictionary<string, ColData>> DtToList(DataTable dt)
        {
            IList<Dictionary<string, ColData>> paseData = new List<Dictionary<string, ColData>>();
            for (int i = 0; i < dt.Rows.Count; i++)
            {
                Dictionary<string, ColData> row = new Dictionary<string, ColData>();
                for (int j = 0; j < dt.Columns.Count; j++)
                {
                    string colName = dt.Columns[j].ColumnName;
                    string colValue = dt.Rows[i][j].ToString(); //原始值
                    if (this.CurParseConf != null && this.CurParseConf.Fields.Count(p => p.Name == colName)>0)
                    {
                        var colconf = this.CurParseConf.Fields.FirstOrDefault(p => p.Name == colName);
                        //数据转换
                        if (!string.IsNullOrEmpty(colconf.ConvertType))
                        {
                            colValue = this.custParseIns[colconf.ConvertType].Parse(colValue, dt.Rows[i].ItemArray, colconf.ConvertParams, extCustParseData);
                        }
                    }
                    row.Add(colName, new ColData()
                    {
                        FieldType = dt.Columns[j].DataType.Name,
                        Value = colValue
                    });
                }

                paseData.Add(row);
            }

            return paseData;
        }
    }
}
